import { ref, onBeforeUnmount } from "vue";
import { GetBaseHostPort } from "./index";
export type WSStatus = "connected" | "connecting" | "close" | "error";

export default function useWebSocket() {
  const messages = ref<any[]>([]);
  const lastMessage = ref<any>();
  const connected = ref<WSStatus>();
  const onMsgReceived = ref<((msg: any) => void)[]>();
  let ws: WebSocket | null = null;
  let hb: number | null = null;

  const onMsg = (fn: (msg: any) => void) => {
    if (onMsgReceived.value) {
      if (onMsgReceived.value.indexOf(fn) === -1) {
        onMsgReceived.value.push(fn);
      }
    } else {
      onMsgReceived.value = [fn];
    }
  };

  const connect = (url: string | URL) => {
    connected.value = "connecting";

    let baseAddr = GetBaseHostPort();
    if (window.location.protocol === "https:") {
      baseAddr = "wss:" + baseAddr;
    } else {
      baseAddr = "ws:" + baseAddr;
    }

    const wsUrl = new URL(url, baseAddr);
    ws = new WebSocket(wsUrl);
    ws.onopen = () => {
      connected.value = "connected";
      hb = window.setInterval(() => ws?.send("ping"), 30_000);
    };
    ws.onmessage = e => {
      messages.value.push(e.data);
      lastMessage.value = e.data;
      if (onMsgReceived.value) {
        try {
          onMsgReceived.value.forEach(fn => fn(e.data));
        } catch (e) {
          console.error(e);
        }
      }
    };

    ws.onclose = () => {
      connected.value = "close";
      hb && clearInterval(hb);
      setTimeout(connect, 3000); // 自动重连
    };
    ws.onerror = e => {
      console.error(e);
      connected.value = "error";
    };
  };

  const send = (data: any) => ws?.send(JSON.stringify(data));
  const close = () => {
    connected.value === "connected" && ws?.close();
  };

  onBeforeUnmount(close);

  return {
    wsMessages: messages,
    wsStatus: connected,
    wsLastMsg: lastMessage,
    wsConnect: connect,
    wsSend: send,
    wsClose: close,
    wsMsgWatch: onMsg
  };
}
